package com.tomtop.core.exception;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.util.MimeType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import com.tomtop.config.WebSiteConfig;
import com.tomtop.core.Context;
import com.tomtop.core._enum.CustomStatus;
import com.tomtop.core.model.ResponseEntity;
import com.tomtop.core.utils.ListUtils;
import com.tomtop.core.utils.MapUtils;

/**
 * 全局API异常
 *
 */
@Controller
@ControllerAdvice
public class GlobalApiExceptionController extends ResponseEntityExceptionHandler{

	private final static Logger logger = LoggerFactory.getLogger(GlobalApiExceptionController.class);
	@Autowired AbstractJackson2HttpMessageConverter jsonConverter;

	@RequestMapping("/exception/notfound") ModelAndView notfound(HttpServletRequest request, HttpServletResponse response ){
		return this.goNewException(request, response, new CustomException(CustomStatus.PAGE_NOT_FOUND));
	}

	@RequestMapping("/exception/server-error") ModelAndView serverError(HttpServletRequest request, HttpServletResponse response){
		String errorMsg = "so sorry,error occured.";
		Exception e = (Exception) request.getAttribute("javax.servlet.error.exception");
		return this.goNewException(request, response, new CustomException(CustomStatus.FAIL, e,e == null ? errorMsg : e.getMessage()));
	}
	
	@ExceptionHandler(CustomException.class) ModelAndView handleControllerException(HttpServletRequest request,HttpServletResponse response, CustomException ex) {
		return this.goNewException(request, response, ex);
	}

	@ExceptionHandler({Throwable.class,IllegalArgumentException.class,NullPointerException.class,}) ModelAndView ControllerException(HttpServletRequest request, HttpServletResponse response, Throwable ex) {
		String errorMsg = "so sorry,error occured.";
		return this.goNewException(request, response, new CustomException(CustomStatus.FAIL, ex,(ex == null || StringUtils.isEmpty(ex.getMessage()))? errorMsg : ex.getMessage()));
	}
    
    /**
     * 去到新的异常处理流程
     * @param request
     * @param response
     * @param ex
     * @return
     */
    private  ModelAndView goNewException(HttpServletRequest request,HttpServletResponse response, CustomException ex) {
    	this.logLevelOut(ex);
    	if(Context.isRest() || this.isJson(request)){
    		return this.jsonView(ResponseEntity.now(ex), response);
    	}
    	return ControllerFromRequestException(request, response,  ex);
    }
    private void logLevelOut(CustomException ex){
    	ListUtils<Object> lu = ListUtils.n().a(ex.getMessage()).a(Context.getContext()) ;
		String format="系统出现了异常{} {}";
		switch (ex.getLevel()) {
		case OFF:
			return;
		case ERROR:
			logger.error(format,lu.a(ex).to().toArray());
			break;
		case WARN:
			logger.warn(format,lu.to().toArray());
			break;
		case INFO:
			logger.info(format,lu.to().toArray());
			break;
		case DEBUG:
			logger.info(format,lu.to().toArray());
			break;
		case TRACE:
			logger.trace(format,lu.to().toArray());
			break;
		default:
			break;
		}
    }
  	/**
  	 * 判断是否需要响应json
  	 * @param request
  	 * @return
  	 */
  	private boolean isJson(HttpServletRequest request){
  		String contenttype = request.getContentType();
  		return !StringUtils.isEmpty(contenttype) && "json".equals(MimeType.valueOf(contenttype).getSubtype().toLowerCase());
  	}
  	/**
  	 * 响应页面
  	 * @param request
  	 * @param response
  	 * @param ex
  	 * @return
  	 */
  	private ModelAndView  ControllerFromRequestException(HttpServletRequest request,HttpServletResponse response,  CustomException ex) {
  		if(ex.getCode()==CustomStatus.USER_NO_LOGIN.code()){
			String backUrl=Context.getRequest().getRequestURL().append("?").append(Context.getRequest().getQueryString()).toString();
			if(logger.isDebugEnabled())
				logger.debug(backUrl);
			String redirectUrl = WebSiteConfig.getLoginBreak(backUrl);
			if(StringUtils.hasText(redirectUrl))
				return new ModelAndView("redirect:"+redirectUrl);
		}
  		
    	String errorMsg="so sorry,error occured";
    	int errorCode=500;
		if(ex!=null ){
			if(StringUtils.hasText(ex.getDetails()))
				errorMsg=ex.getDetails();
			else if(StringUtils.hasText(ex.getDescribe()))
				errorMsg = ex.getDescribe();
			errorCode=ex.getCode();
		}
		
		String url="order/pay_fail";
		if(ex!=null&&ex.getGoUrl()!=null)
			url=ex.getGoUrl();
		  if(!Context.isPc()&&!url.startsWith("redirect")){ url="mobile/"+url; }
		ModelAndView modelAndView= new ModelAndView(url);
		String breakurl=WebSiteConfig.getCartHome();//触发异常去到首页 
		String continueUrl=WebSiteConfig.getShopHome();
		modelAndView.addAllObjects(MapUtils.<String, Object>n().
				a("breakUrl", breakurl).
				a("continueUrl", continueUrl).
				a("errorCode", errorCode).
				a("errorMsg", errorMsg).
				a("customerservice", WebSiteConfig.getWebSite().getService()).
				to());
		return modelAndView;
    }
  	/**
  	 * 响应json
  	 * @param model
  	 * @param response
  	 * @return
  	 */
  	private ModelAndView jsonView(Object model, HttpServletResponse response)
     {
         try {
			jsonConverter.write(model, MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
		} catch (HttpMessageNotWritableException | IOException e) {
			e.printStackTrace();
		}
        return null;
     }
}
